$OpenBSD: patch-server_gam_kqueue_c,v 1.8 2012/12/18 21:38:12 sthen Exp $

From FreeBSD:
Make sure that excluded paths do not get opened (but rather they will be
polled).

OpenBSD doesn't have sysctlbyname, use sysctl(3) instead.

Enable the polling backend along with kqueue, making NFS work again.

Fix "enumeration value... not handled in switch" warnings.

OpenBSD does not have maxfilesperproc, which means max_open_files will
default to "0" and kqueue will never be used. Instead, use get+setrlimit
to get a correct value.

--- server/gam_kqueue.c.orig	Wed Jul  4 07:50:41 2007
+++ server/gam_kqueue.c	Thu Dec  6 16:04:59 2012
@@ -31,7 +31,8 @@
  *           - kqueue needs to be moved out the UFS code.
  *
  * Copyright (C) 2005 Joe Marcus Clarke <marcus@FreeBSD.org>
- * Copyright (C) 2005 Jean-Yves Lefort <jylefort@FreeBSD.org>
+ * Copyright (C) 2005, 2006 Jean-Yves Lefort <jylefort@FreeBSD.org>
+ * Copyright (C) 2006 Alex Dupre <ale@FreeBSD.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -53,15 +54,19 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/param.h>
+#include <sys/proc.h>
 #include <sys/types.h>
 #include <sys/sysctl.h>
 #include <sys/stat.h>
 #include <sys/event.h>
 #include <sys/time.h>
+#include <sys/mount.h>
+#include <err.h>
 #include <errno.h>
 #include "gam_error.h"
 #include "gam_kqueue.h"
 #include "gam_event.h"
+#include "gam_excludes.h"
 #include "gam_server.h"
 #include "gam_poll_basic.h"
 
@@ -323,20 +328,6 @@ gam_kqueue_isdir (const char *pathname, MonitorFlags f
     }
 }
 
-static gboolean
-gam_kqueue_get_uint_sysctl (const char *name, unsigned int *value)
-{
-  unsigned int value_len = sizeof(*value);
-
-  if (sysctlbyname(name, value, &value_len, (void *)NULL, 0) < 0)
-    {
-      gam_error(DEBUG_INFO, "unable to retrieve %s: %s\n", name, g_strerror(errno));
-      return FALSE;
-    }
-  else
-    return TRUE;
-}
-
 /*** HashTable ***************************************************************/
 
 static HashTable *
@@ -509,33 +500,49 @@ static gboolean
 gam_kqueue_monitor_enable_kqueue (Monitor *mon)
 {
   struct kevent ev[1];
+  struct statfs sb;
 
   if (open_files == max_open_files)
     {
       GAM_DEBUG(DEBUG_INFO, "cannot open %s (max_open_files limit reached), falling back to poll\n", mon->pathname);
       return FALSE;
     }
-  
-  mon->fd = open(mon->pathname, O_RDONLY | O_NOFOLLOW);
+ 
+  if (gam_exclude_check(mon->pathname))
+    {
+      GAM_DEBUG(DEBUG_INFO, "not using kqueue for %s since it is excluded, falling back to poll\n", mon->pathname);
+      return FALSE;
+    }
+
+  mon->fd = open(mon->pathname, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
   if (mon->fd < 0)
     {
       GAM_DEBUG(DEBUG_INFO, "cannot open %s (%s), falling back to poll\n", mon->pathname, g_strerror(errno));
       return FALSE;
     }
 
+  if (fstatfs(mon->fd, &sb) == 0 && (sb.f_flags & MNT_LOCAL) == 0)
+    {
+      GAM_DEBUG(DEBUG_INFO, "%s resides on a remote file system, falling back to poll\n", mon->pathname);
+      goto poll;
+    }
+
   EV_SET(ev, mon->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, VN_NOTE_ALL, 0, mon);
   if (kevent(kq, ev, G_N_ELEMENTS(ev), NULL, 0, NULL) < 0)
     {
       GAM_DEBUG(DEBUG_INFO, "cannot enable kqueue notification for %s (%s), falling back to poll\n", mon->pathname, g_strerror(errno));
 
-      close(mon->fd);
-      mon->fd = -1;
-
-      return FALSE;
+      goto poll;
     }
 
   open_files++;
   return TRUE;
+
+ poll:
+  close(mon->fd);
+  mon->fd = -1;
+
+  return FALSE;
 }
 
 static void
@@ -840,6 +847,9 @@ gam_kqueue_sub_monitor_emit_event (SubMonitor *smon,
     case GAMIN_EVENT_MOVED:
       gam_kqueue_sub_monitor_set_missing(smon);
       break;
+
+    default:
+      break;
     }
 
   gam_server_emit_event(mon->pathname, isdir, event, smon->subs, 1);
@@ -981,6 +991,9 @@ gam_kqueue_file_monitor_emit_event (FileMonitor *fmon,
 	
       gam_kqueue_hash_table_remove(fmon->smon->fmons, fmon);
       break;
+
+    default:
+      break;
     }
 }
 
@@ -1125,7 +1138,12 @@ gam_kqueue_init (void)
   GIOChannel *channel;
   unsigned int maxfiles;
   unsigned int maxfilesperproc;
+  int mib[2];
+  size_t len;
+  struct rlimit rlp;
 
+  gam_poll_basic_init ();
+
   kq = kqueue();
   if (kq < 0)
     {
@@ -1133,11 +1151,16 @@ gam_kqueue_init (void)
       return FALSE;
     }
 
-  if (! gam_kqueue_get_uint_sysctl("kern.maxfiles", &maxfiles))
+  len = sizeof(maxfiles);
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_MAXFILES;
+
+  if (sysctl(mib, 2, &maxfiles, &len, NULL, 0) < 0) {
+	gam_error(DEBUG_INFO, "unable to retrieve maxfiles: %s\n", g_strerror(errno));
     return FALSE;
-  if (! gam_kqueue_get_uint_sysctl("kern.maxfilesperproc", &maxfilesperproc))
-    return FALSE;
+}
 
+
   /*
    * We make sure to:
    *	- never paralyze the system (CFG_GLOBAL_FILE_RESERVE_RATIO)
@@ -1145,6 +1168,22 @@ gam_kqueue_init (void)
    */
 
   maxfiles *= CFG_GLOBAL_FILE_RESERVE_RATIO;
+  maxfilesperproc = 128;
+
+  if (getrlimit(RLIMIT_NOFILE, &rlp) == 0)
+    {
+      rlp.rlim_cur = rlp.rlim_max;
+      if (setrlimit(RLIMIT_NOFILE, &rlp) < -1)
+        {
+          gam_error(DEBUG_INFO, "cannot unlimit number of open files\n");
+          err(1, "setrlimit");
+        }
+      else
+        {
+          maxfilesperproc = rlp.rlim_max;
+        }
+    }
+
   maxfilesperproc = maxfilesperproc > CFG_SELF_FILE_RESERVE
     ? maxfilesperproc - CFG_SELF_FILE_RESERVE
     : 0;
